package com.example.weightsmartlightapp;

import android.Manifest;
import android.bluetooth.BluetoothDevice;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import gao.xiaolei.blue.BlueToothController;
import gao.xiaolei.blue.callback.ConnectCallback;
import gao.xiaolei.blue.callback.OnReceiverCallback;
import gao.xiaolei.blue.callback.OnWriteCallback;
import gao.xiaolei.blue.callback.ScanCallback;
import gao.xiaolei.blue.util.HexUtil;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL_METHOD = "my.flutter.io/bluetooth";
    private static final String EVENT_CHANNEL = "my.flutter.event/bluetooth";
    private Map<String,BlueToothController> blueControllerMap=new HashMap<>();//用map来储存蓝牙Controller对象,减少代码的冗余
    private List<EventChannel.EventSink> skinList=new LinkedList<EventChannel.EventSink>();//flutter中订阅了要接收我发出的消息的观察者们
    private Handler mHandler = new Handler(Looper.getMainLooper());//handle的作用是为了在主线程中向flutter返回消息,Flutter1.7.8版本添加了线程安全，需要原生在主线程中返回给Flutter
    private ScanCallback scanCallback=new ScanCallback() {
        @Override
        public void onSuccess(BlueToothController controller) {
            if(!controller.isScannedTarget()) {//如果扫描结束了还没有扫描到目标设备就肯定连接不上了
                System.out.println("扫描不到目标设备！");
                String deviceName=controller.getDeviceName();//获取该controller的deviceName
                blueControllerMap.remove(controller);//将controller从map中移除
                sendFailMsgToEventChannel("90001", "扫描不到目标设备", deviceName);//向flutter发送消息
            }
        }

        @Override
        public void onScanning(BluetoothDevice device) {
            System.out.println("扫描到一个！");
        }
    };

    private ConnectCallback connectCallback=new ConnectCallback() {
        @Override
        public void onConnSuccess(BlueToothController controller) {
            System.out.println("连接成功！");
            String deviceName=controller.getDeviceName();
            Map<String,Object> successData=new HashMap<>(2);
            successData.put("code","80001");
            successData.put("deviceName",deviceName);
            sendSuccessMsgToEventChannel(successData);//向flutter发送连接成功的消息
        }

        @Override
        public void onConnFailed(BlueToothController controller) {
            if(controller.isInitiativeToDisconnect()){//如果是自己手动断开连接的话
                System.out.println("连接被手动断开");
                Map<String,Object> successData=new HashMap<>(2);
                successData.put("deviceName",controller.getDeviceName());
                successData.put("code","80002");
                blueControllerMap.remove(controller);//将controller从map中移除
                sendSuccessMsgToEventChannel(successData);
            }else{//如果是被动断开的话
                System.out.println("连接自己断开");
                blueControllerMap.remove(controller);//将controller从map中移除
                sendFailMsgToEventChannel("90002","与设备的连接断开",controller.getDeviceName());
            }
        }
    };

    private OnWriteCallback onWriteCallback=new OnWriteCallback() {
        @Override
        public void onSuccess(String characteristicUuid) {
            System.out.println("特征值：".concat(characteristicUuid).concat("写入成功！"));
        }

        @Override
        public void onFailed(String characteristicUuid, int state) {
            System.out.println("特征值：".concat(characteristicUuid).concat("写入失败！").concat("state:").concat(String.valueOf(state)));
        }
    };
    private OnReceiverCallback receiverCallback= (controller,characteristicUuid, value) -> {
        System.out.println("notify特征值：".concat(characteristicUuid).concat("传来数据：").concat(HexUtil.bytesToHexString(value)));
        Map<String,Object> notifyData=new HashMap<>(4);
        String deviceName=controller.getDeviceName();
        notifyData.put("code","80005");
        notifyData.put("deviceName",deviceName);
        notifyData.put("notifyUuid",characteristicUuid);
        notifyData.put("data",value);
        sendSuccessMsgToEventChannel(notifyData);//向flutter发送notify传回来的消息
    };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new EventChannel(this.getFlutterView(), EVENT_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {//创建对flutter的消息发送channel
            @Override
            public void onListen(Object o, EventChannel.EventSink eventSink) {//当flutter中有人要订阅我们发送的消息时就会调用这个函数
                skinList.add(eventSink);//将观察者加入list中
            }
            @Override
            public void onCancel(Object o) {//当flutter中有人要取消订阅我们发送的消息时就会调用这个函数
                skinList.remove(o);//将观察者移除
            }
        });
        new MethodChannel(getFlutterView(), CHANNEL_METHOD).setMethodCallHandler(//接收上层flutter对android的方法调用
                (call, result) -> {
                    switch (call.method){
                        case "connectDevice"://如果是要去连接蓝牙设备的话
                            System.out.println("去连接设备啦");
                            Map<String,Object> connectDataMap=call.arguments();
                            BlueToothController controller= BlueToothController.getInstance(
                                    (int)connectDataMap.get("uuidDataType"),
                                    (String)connectDataMap.get("deviceUuid"),
                                    (String)connectDataMap.get("notify_d"),
                                    (String)connectDataMap.get("notifyUuid"),
                                    this);
                            controller.setDeviceName((String)connectDataMap.get("deviceName"));
                            controller.setScanCallback(scanCallback);
                            controller.setConnectCallback(connectCallback);
                            controller.setReceiverCallback(receiverCallback);
                            controller.setWriterCallback(onWriteCallback);
                            blueControllerMap.put(controller.getDeviceName(),controller);
                            controller.connectDriver();//连接设备
                            result.success("80003");//跟flutter报告说开始去连接设备了
                            break;
                        case "applyBlueAuth"://如果是要去申请设备权限的话
                            local();
                            result.success("80004");//跟flutter报告说开始去连接设备了
                            break;
                        case "sendData"://如果是向设备发送数据的话
                            Map<String,Object> sendDataMap=call.arguments();
                            BlueToothController targetController=blueControllerMap.get((String)sendDataMap.get("deviceName"));
                            targetController.sendData(
                                    (String)sendDataMap.get("serviceUuid"),
                                    (String)sendDataMap.get("writeUuid"),
                                    (String)sendDataMap.get("notifyUuid"),
                                    (byte[]) sendDataMap.get("data"),
                                    (boolean) sendDataMap.get("isWithResult"));
                            break;
                        case "disConnectDevice"://如果是手动断开连接
                            System.out.println("要去断开连接啦");
                            BlueToothController disConnectController=blueControllerMap.get((String)call.arguments());
                            disConnectController.disConnectDriver();
                            break;
                        default://如果没有此方法
                            result.notImplemented();
                            break;
                    }
                });
    }

    //向观察者们轮询发送成功消息
    private void sendSuccessMsgToEventChannel(Object msg){
        for(EventChannel.EventSink e:skinList){
            runOnMainThread(()->{
                e.success(msg);
            });
        }
    }

    //向观察者们轮询发送失败消息
    private void sendFailMsgToEventChannel(String errCode, String errMsg, Object errDetail){
        for(EventChannel.EventSink e:skinList){
            runOnMainThread(()-> {
                e.error(errCode,errMsg,errDetail);
            });
        }
    }

    /**
     * 判断是否具有权限
     */
    private void local() {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
            Log.i("dd", "sdk < 28 Q");
            if (ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                String[] strings =
                        {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
                ActivityCompat.requestPermissions(this, strings, 1);
            }
        } else {
            if (ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(this,
                    "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
                String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
                        android.Manifest.permission.ACCESS_COARSE_LOCATION,
                        "android.permission.ACCESS_BACKGROUND_LOCATION"};
                ActivityCompat.requestPermissions(this, strings, 2);
            }
        }
    }

    /**
     * 判断当前线程是否是主线程
     *
     */
    private boolean isMainThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    /**
     * 将目标代码快运行在主线程中
     *
     */
    private void runOnMainThread(Runnable runnable) {
        if (isMainThread()) {
            runnable.run();
        } else {
            if (mHandler != null) {
                mHandler.post(runnable);
            }
        }
    }
}
